package com.swak.fx.support.ui;

import java.util.Objects;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Control;
import javafx.scene.image.WritableImage;

/**
 * UISnapshot. 
 * 
 * @author 618lf
 */
public class UISnapshot extends Control implements UILifecycle {

	private final ObjectProperty<Node> node;
	private final ObjectProperty<Rectangle2D> selection;

	public UISnapshot() {
		node = new SimpleObjectProperty<>(this, "node"); //$NON-NLS-1$
		selection = new SimpleObjectProperty<Rectangle2D>(this, "selection") { //$NON-NLS-1$
			@Override
			public void set(Rectangle2D selection) {
				if (!isSelectionValid(selection)) {
					throw new IllegalArgumentException("The selection \"" + selection + "\" is invalid. " + //$NON-NLS-1$ //$NON-NLS-2$
					"Check the comment on 'SnapshotView.selectionProperty()' " + //$NON-NLS-1$
					"for all criteria a selection must fulfill."); //$NON-NLS-1$
				}
				super.set(selection);
			}
		};
	}

	public UISnapshot(Node node) {
		this();
		setNode(node);
	}

	public final ObjectProperty<Rectangle2D> selectionProperty() {
		return selection;
	}

	public final Rectangle2D getSelection() {
		return selectionProperty().get();
	}

	public final ObjectProperty<Node> nodeProperty() {
		return node;
	}

	public final Node getNode() {
		return nodeProperty().get();
	}

	public final void setNode(Node node) {
		nodeProperty().set(node);
	}

	public final boolean hasSelection() {
		return selectionProperty().get() != null;
	}

	private boolean isSelectionValid(Rectangle2D selection) {
		// empty selections are valid
		boolean emptySelection = selection == null || selection == Rectangle2D.EMPTY;
		if (emptySelection) {
			return true;
		}

		// check values
		if (!valuesFinite(selection)) {
			return false;
		}
		return true;
	}

	private static boolean valuesFinite(Rectangle2D selection) {
		return Double.isFinite(selection.getMinX()) && Double.isFinite(selection.getMinY())
				&& Double.isFinite(selection.getWidth()) && Double.isFinite(selection.getHeight());
	}

	public WritableImage createSnapshot() throws IllegalStateException {
		// make sure the node and the selection exist
		if (getNode() == null) {
			throw new IllegalStateException("No snapshot can be created if the node is null (check 'getNode()')."); //$NON-NLS-1$
		}
		if (!hasSelection()) {
			throw new IllegalStateException(
					"No snapshot can be created if there is no selection (check 'hasSelection()')."); //$NON-NLS-1$
		}

		SnapshotParameters parameters = new SnapshotParameters();
		parameters.setViewport(getSelection());
		return createSnapshot(parameters);
	}

	public WritableImage createSnapshot(SnapshotParameters parameters) throws IllegalStateException {
		// make sure the node and the snapshot parameters exist
		Objects.requireNonNull(parameters, "The argument 'parameters' must not be null."); //$NON-NLS-1$
		if (getNode() == null) {
			throw new IllegalStateException("No snapshot can be created if the node is null (check 'getNode()')."); //$NON-NLS-1$
		}

		// take the snapshot
		return getNode().snapshot(parameters, null);
	}
	
	
}